-
Notifications
You must be signed in to change notification settings - Fork 276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Scala Native support #2846
base: master
Are you sure you want to change the base?
Add Scala Native support #2846
Conversation
Project structure was changed in compliance with sbt-crossproject to accomodate Scala Native support. Co-authored-by: Tomasz Godzik <tgodzik@users.noreply.github.com>
Project structure was changed in compliance with sbt-crossproject. googlecode's diffutils had to be removed, as Scala Native does not support java libraries. In its place, part of diffutils was reimplemented in scala as part of scalafmt-cli. For similar reasons, the java interfaces were reimplemented in scala for Scala Native. Since Scala Native does not yet support glob expressions, a translation function to regex was added, heavily based on a linked stack-overflow answer. Similarly, Scala's Process is replaced with java stdlib's ProcessBuilder, as Process uses concurrency. SN's regex implementation is currently based on the re2 instead of the standard java regexes. This means there are a number of differences between them, most notably the lack of backtracking in Scala Native. To accomodate that, some regex function reimplementations were done to accomodate the use of the existing scalafmt regexes in Scala Native. Some operations concerning tests were slightly modified to work on Native. For example, renaming a file to an existing directory path could throw errors. This is fine, as it does not concern the core of the test, only things like cleanup. Assumptions about dynamic tests not working on native were added. Scala Native does not support URLs and only has basic reflection support comparable to the one of GraalVM, so the used and expected version of scalafmt must match here as well. Term Display was made single-threaded for the Scala Native implementation, as it does not support concurrency. Since the new implementation caused display artifacts on JVM, the old multithreaded one was kept there. Scala Native setup and testing was added to the CI. The windows was temporarily disabled as it does not pass all of the tests. scala-native sbt command was also added for easier scala-native cli building. Co-authored-by: Tomasz Godzik <tgodzik@users.noreply.github.com>
69f6f29
to
5b48eed
Compare
@jchyb massive amount of work, kudos! i like your decision to rename in a separate commit. I'd like to suggest that we split the second one into several more focused commits, such as turning projects into cross projects, adding each replacement one at a time (for diffutils etc.). in fact, maybe even split into a couple of pull requests. reviewing 300 files is scary. 😀 |
Most of the work was honestly done by Tomasz, as was it his idea to do a separate commit. I can of course split it into further commits with files concerning separate changes later today. Personally, I would prefer keeping it all in this PR, as I fear the merging could otherwise become messy and now its easier to rebase if necessary. In case of potential review findings/concerns, I can be updating the individual commits, so that we don't have to use the now-dreaded "Files changed" tab ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very, very incomplete review. definitely lots of changes which can be submitted and merged separately.
also, would strongly prefer that every commit result in valid, compilable, testable code and could be separated or reverted by itself.
@@ -0,0 +1,262 @@ | |||
package org.scalafmt.cli |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- file name itself contains a typo
- is this copied from somewhere? complex code.
@@ -81,7 +81,7 @@ To build a native image of the command-line interface using | |||
|
|||
- From the project root directory, | |||
- run `sbt cli/assembly` | |||
- run `java -jar scalafmt-cli/target/scala-2.13/scalafmt.jar`, to execute recently built artifacts | |||
- run `java -jar scalafmt-cli/jvm/target/scala-2.13/scalafmt.jar`, to execute recently built artifacts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i assumed that no suffix for jvm meant perhaps that jvm wouldn't be added here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately that's how cross building works in this case. We could probably override it for jvm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No suffix only works for for the sbt commands I think, so f.e. in the cross project instead of cliJVM/run we only need to run cli/run for the JVM platform in this branch. The idea was to keep the previously used commands intact.
@@ -174,15 +210,6 @@ lazy val cli = project | |||
val oldStrategy = (assembly / assemblyMergeStrategy).value | |||
oldStrategy(x) | |||
}, | |||
libraryDependencies ++= Seq( | |||
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0", | |||
"com.martiansoftware" % "nailgun-server" % "0.9.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this dependency remains. why not keep it here, instead pushing down?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's probably my bad, experimented a lot with the project and kind of left a mess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i must have misunderstood what that no suffix call does. just wanted to make sure this is correct.
@@ -0,0 +1,280 @@ | |||
package org.scalafmt.cli |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing in common with the other version?
@@ -22,11 +22,10 @@ object ScalafmtCoreRunner extends ScalafmtRunner { | |||
ExitCode.UnexpectedError | |||
} { scalafmtConf => | |||
options.common.debug.println(s"parsed config (v${Versions.version})") | |||
val filterMatcher = ProjectFiles.FileMatcher( | |||
lazy val filterMatcher = ProjectFiles.FileMatcher( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this needed?
@@ -0,0 +1,26 @@ | |||
package org.scalafmt.interfaces |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the difference with non native version? should we simply move from Java to scala in the original?
// native - FileNotFoundException, JVM - NoSuchFileException | ||
assert( | ||
confError.cause.exists(err => | ||
err.isInstanceOf[NoSuchFileException] || err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
break line, looks bad
@@ -104,7 +105,13 @@ class CliOptionsTest extends FunSuite { | |||
val opt = baseCliOptions.copy(config = Some(configPath.toFile)) | |||
assert(opt.scalafmtConfig.isInstanceOf[Configured.NotOk]) | |||
val confError = opt.scalafmtConfig.asInstanceOf[Configured.NotOk].error | |||
assert(confError.cause.exists(_.isInstanceOf[NoSuchFileException])) | |||
// native - FileNotFoundException, JVM - NoSuchFileException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and we can't use the same in both cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jchyb If you haven't already, an issue should be filed in Scala Native.
val label = if (version == Versions.version) "core" else "dynamic" | ||
val (label, isDynamic) = | ||
if (version == Versions.version) ("core", false) else ("dynamic", true) | ||
def assumeNotDynamicOnNative(): Unit = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't we just call this once?
@@ -70,9 +70,10 @@ class GitOpsTest extends FunSuite { | |||
dir.orElse(ops.rootDir).get.jfile.toPath, | |||
"dir_" | |||
) | |||
val destPath = destDir.resolve("new_file") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like perfect candidate for separate pr
Thanks @jchyb for following up with the PR and thanks @kitbellew for the review! I don't expect to have this merged right away and we should come up with a plan what are the parts that we can merge separately and ones that we can split over multiple commits. I will talk with @jchyb how we can go about it. |
Just thinking about it now we could split it at least into:
|
great idea (both)
preparing jvm changes for native counterpart as part of that (such as regex refactors, term display, sys process etc.)
|
is this still possible to get merged? |
I think this requires a bit more time, which we currently don't have, so if anyone would be willing to spend some time on it that would be awesome. |
Getting the difflib made into a scalameta project would be great. I asked Wojciech if it might work for our uses in Scala Native too. |
I think this PR is big ,maybe can be splitter and deliver in batchs. |
@He-Pin Yes, that is what @kitbellew suggests above. The |
We usually inline it as it's rather small, so we never had any will to make it a separate library. |
Changes
Project structure was changed in compliance with
sbt-crossproject
.googlecode
'sdiffutils
had to be removed, as Scala Native does not support java libraries. In its place, part of diffutils was reimplemented in scala as part of scalafmt-cli.For similar reasons, the java interfaces were reimplemented in scala for Scala Native.
Since Scala Native does not yet support glob expressions, a translation function to regex was added, heavily based on a linked stack-overflow answer. Similarly, Scala's
Process
is replaced with java stdlib'sProcessBuilder
, asProcess
uses concurrency.SN's regex implementation is currently based on the re2 instead of the standard java regexes. This means there are a number of differences between them, most notably the lack of backtracking in Scala Native. To accommodate that, some regex function reimplementations were done to match the use of the existing scalafmt regexes in Scala Native.
Some operations concerning tests were slightly modified to work on Native. For example, renaming a file to an existing directory path could throw errors. Hopefully this is fine, as it does not concern the core of the test, only things like cleanup.
Assumptions about dynamic tests not working on native were added. Scala Native does not support URLs and only has basic opt-in reflection support comparable to the one of GraalVM, so the used and expected version of scalafmt must match here as well.
Term Display was made single-threaded for the Scala Native, as SN does not support concurrency yet. Since the new implementation caused display artifacts on JVM, the old multithreaded one was kept there.
Scala Native setup and testing was added to the CI. Windows support was temporarily disabled as it does not pass all of the tests yet.
scala-native
sbt command was also added for easier scala-native cli building. Usesbt scala-native
to generate Scala Native binaries (with LLVM installed).Publishing
I did not include any publishing in this PR. For now there is not much point in releasing the scala-native binaries. Publishing as a library is another story, but I have not looked into that yet.
Performance
There are some severe performance problems when using the binaries generated from Scala Native. This should not happen. I tried to move the regex reimplementation as well as TermDisplay to use in JVM, yet that did not cause any noticeable performance problems there - unfortunately it seems that there is a bug on scala-native side. I will try to look into that issue.
Comparison running on Scalafmt repo:
JVM:
Native (Immix GC, release-fast optimization mode, full LTO, but I tried with many more options to no avail):
Additional comments
To smoothen out the review process I split this PR into two commits, one with only renames, and one with more meaningful changes. Hopefully this will help a bit :)